package com.ynding.cloud.auth.authentication.controller;

import com.ynding.cloud.auth.authentication.service.IAuthenticationService;
import com.ynding.cloud.common.model.bo.ResponseBean;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Collection;

/**
 * <p> </p>
 *
 * @author ynding
 * @version 2021/6/18
 **/
@RestController
@RequestMapping("/oauth")
@Api(value = "OAuth", tags = {"OAuth-Controller"})
public class OauthController {

    @Autowired
    private DefaultTokenServices tokenServices;
    @Autowired
    private OAuth2RestTemplate restTemplate;
    @Autowired
    private IAuthenticationService authenticationService;

    @GetMapping("/access_token")
    @ApiOperation(value = "获取token", produces = "application/json")
    public ResponseBean getAccessToken() {
        OAuth2AccessToken auth2AccessToken = restTemplate.getAccessToken();
        return ResponseBean.ok(auth2AccessToken);
    }

    @GetMapping("/revoke_token")
    @ApiOperation(value = "注销token", produces = "application/json")
    public ResponseBean revokeToken(@RequestParam("token") String access_token) {
        if (tokenServices.revokeToken(access_token)) {
            return ResponseBean.ok();
        } else {
            return ResponseBean.fail("注销失败");
        }
    }

    /**
     * 是否无效authentication
     *
     * @param access_token
     * @return
     */
    @GetMapping("/invalidJwtAccessToken")
    @ApiOperation(value = "是否无效authentication", produces = "application/json")
    public ResponseBean invalidJwtAccessToken(@RequestParam("authentication") String access_token) {
        if (authenticationService.invalidJwtAccessToken(access_token)) {
            // 无效
            return ResponseBean.ok();
        }
        return ResponseBean.fail();
    }

    @GetMapping("/authorities")
    @ApiOperation(value = "token中的角色", produces = "application/json")
    public ResponseBean authorities(@RequestParam("token") String access_token) {
        OAuth2Authentication oAuth2Authentication = tokenServices.loadAuthentication(access_token);
        Collection<GrantedAuthority> authorities = oAuth2Authentication.getAuthorities();
        return ResponseBean.ok(authorities);
    }

    @PostMapping("/auth/isPermission")
    @ApiOperation(value = "是否有权访问url,method", produces = "application/json")
    public ResponseBean<Boolean> isPermission(@RequestParam String url, @RequestParam String method, HttpServletRequest request) {
        boolean decide = authenticationService.decide(new HttpServletRequestAuthWrapper(request, url, method));
        return ResponseBean.ok(decide);
    }

    @PostMapping("/auth/permission")
    @ApiOperation(value = "是否有权访问url,method", produces = "application/json")
    ResponseBean<Boolean> auth(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorization, @RequestParam("url") String url, @RequestParam("method") String method) {
        boolean permission = authenticationService.auth(authorization, url, method);
        return ResponseBean.ok(permission);
    }

    /**
     * 请求包装类
     */
    class HttpServletRequestAuthWrapper extends HttpServletRequestWrapper {
        private String url;
        private String method;

        /**
         * @param url
         * @param method
         */
        public HttpServletRequestAuthWrapper(HttpServletRequest request, String url, String method) {
            super(request);
            this.url = url;
            this.method = method;
        }

        @Override
        public String getMethod() {
            return this.method;
        }

        @Override
        public String getServletPath() {
            return this.url;
        }
    }

}
